#include "cst816d.h"
#include <stddef.h>

void cst816d_reset(struct cst816d* tp)
{
	if (NULL == tp) {
		return;
	}

	/* the spec requires at least 5ms */
	tp->ops.reset(LOW);
	tp->ops.msleep(10);

	/* the spec requires a maximum wait of 100 */
	tp->ops.reset(HIGH);
	tp->ops.msleep(120);
}

int cst816d_init(struct cst816d* tp)
{
	int ret = 0;
	uint8_t val = 0;

	if (NULL == tp) {
		return -1;
	}

	/* set touch panel 7bit i2c slave address */
	tp->cfg.fix.slave_address = 0x15;

	/* reset sequence */
	cst816d_reset(tp);

	/* configuration the moion mask */
	/*
	[2] EnConLR - Continuous operation can slide around
	[1] EnConUD - Slide up and down to enable continuous operation
	[0] EnDClick - Enable Double-click action
	*/
	val = 0x03;
	ret = tp->ops.write(CST816D_REG_MOTION_MASK, &val, 1);
	if (ret) {
		return -1;
	}

	/* configuration the irq control */
	/*
	[7] EnTest - Interrupt pin to test, enable automatic periodic issued after a low pulse.
	[6] EnTouch - When a touch is detected, a periodic pulsed Low.
	[5] EnChange - Upon detecting a touch state changes, pulsed Low.
	[4] EnMotion - When the detected gesture is pulsed Low.
	[0] OnceWLP - Press gesture only issue a pulse signal is low.
	*/
	val = 0x70;
	ret = tp->ops.write(CST816D_REG_IRQ_CTRL, &val, 1);
	if (ret) {
		return -1;
	}

	return 0;
}

void cst816d_deinit(struct cst816d* tp)
{
	if (NULL == tp) {
		return;
	}

	/* do nothing */
	return;
}

int cst816d_sleepin(struct cst816d* tp)
{
	if (NULL == tp) {
		return -1;
	}

	int ret = 0;
	uint8_t val = 0;

	/* reset sequence */
	cst816d_reset(tp);

	val = 0x03;
	ret = tp->ops.write(CST816D_REG_WORK_MODE, &val, 1);
	if (ret) {
		return -1;
	}

	return 0;
}

int cst816d_wakeup(struct cst816d* tp)
{
	if (NULL == tp) {
		return -1;
	}

	return cst816d_init(tp);
}

int cst816d_get_info(struct cst816d* tp, uint8_t* chip, uint8_t* vendor, uint8_t* version)
{
	int ret = 0;
	uint8_t val[3] = { 0 };

	if (NULL == tp || NULL == chip || NULL == vendor || NULL == version) {
		return -1;
	}

	/* read 0xA7 ~ 0xA9 reg's values */
	ret = tp->ops.read(CST816D_REG_CHIP_ID, val, 3);
	if (ret) {
		return -1;
	}

	/* convert to infomation */
	*chip = val[0];
	*vendor = val[1];
	*version = val[2];

	return 0;
}

int cst816d_get_coord(struct cst816d* tp, bool* pressed, uint16_t* x, uint16_t* y)
{
	uint8_t gesture = 0;
	return cst816d_get_gesture(tp, &gesture, pressed, x, y);
}

int cst816d_get_gesture(struct cst816d* tp, uint8_t* gestrue, bool* pressed, uint16_t* x, uint16_t* y)
{
	int ret = 0;
	uint8_t val[7] = { 0 };

	if (NULL == tp || NULL == gestrue || NULL == x || NULL == y) {
		return -1;
	}

	/* read 0x00 ~ 0x06 reg's values */
	ret = tp->ops.read(0x00, val, 7);
	if (ret) {
		*pressed = false;
		*gestrue = CST816D_GESTURE_NONE;
		*x = 0;
		*y = 0;
		return -1;
	}

	/* calculate the xy coordinates */
	*x = ((val[CST816D_REG_XPOS_HIGH] & 0x0f) << 8) | val[CST816D_REG_XPOS_LOW];
	*y = ((val[CST816D_REG_YPOS_HIGH] & 0x0f) << 8) | val[CST816D_REG_YPOS_LOW];
	if (*x >= tp->cfg.fix.width || *y >= tp->cfg.fix.height) {
		*pressed = false;
		*gestrue = CST816D_GESTURE_NONE;
		*x = 0;
		*y = 0;
		return -2;
	}

	/* record pressed status by touch points number */
	if (val[CST816D_REG_FINGER_NUM]) {
		*pressed = true;
	} else {
		*pressed = false;
	}

	*gestrue = val[CST816D_REG_GESTURE_ID];
	return 0;
}